﻿// The MIT License (MIT)
// Copyright (c) 2013 Stylianos Dritsas
//
// Permission is hereby granted, free of charge, to any person obtaining a 
// copy of this software and associated documentation files (the "Software"), 
// to deal in the Software without restriction, including without limitation 
// the rights to use, copy, modify, merge, publish, distribute, sublicense, 
// and/or sell copies of the Software, and to permit persons to whom the 
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included 
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
// DEALINGS IN THE SOFTWARE.

//-- System Imports
//--
using System;
using System.Collections.Generic;
using BulletSharp;

//-- Disambiguation / Aliases
//--
using Mat4D    = BulletSharp.Matrix;
using Vec3D    = BulletSharp.Vector3;
using World    = BulletSharp.DynamicsWorld;
using Phase    = BulletSharp.BroadphaseInterface;
using Config   = BulletSharp.CollisionConfiguration;
using Shapes   = BulletSharp.AlignedCollisionShapeArray;
using Dispatch = BulletSharp.CollisionDispatcher;
using Solver   = BulletSharp.SequentialImpulseConstraintSolver;

namespace Sutd
{
  #region -- Simulation Data ------------------------------------------------

  public class Physics
  {
    public static Physics Instance;

    //-- Bullet/Rhino Data
    //--
    public class Body
    {
      public RigidBody rigid;    //-- Bullet Body  
      public int       solid;    //-- Parasolid Body
      public Mat4D     matrix;   //-- Tranformation 
    }

    //-- Body Array
    //--
    public class Bodies : List<Body> { }

    public Config   config;        //-- Collision Configuration
    public Dispatch dispatch;      //-- Collision Dispatcher
    public Phase    phase;         //-- Collision Broadphase
    public Solver   solver;        //-- Constraint Solver
    public World    world;         //-- Collision World
    public Shapes   shapes;        //-- Collision Shapes
    public Bodies   bodies;

    public Physics( )
    {
      config   = new DefaultCollisionConfiguration( );
      dispatch = new CollisionDispatcher( config );
      phase    = new DbvtBroadphase( );
      solver   = new Solver( );
      world    = new DiscreteDynamicsWorld( dispatch, phase, solver, config );
      shapes   = new AlignedCollisionShapeArray( );
      bodies   = new Bodies( );
    }

    #region -- Cleanup ------------------------------------------------------

    public void Reset( )
    {
      try
      {
        //-- Delete Rigid Bodies and Constraints
        //-- (as in the bullet folk-lift demo)
        //--
        for( var index = world.CollisionObjectArray.Count - 1; index >= 0; index-- )
        {
          var obj = world.CollisionObjectArray[index];
          var body = obj as RigidBody;
          if( ( body != null ) && ( body.MotionState != null ) )
          {
            while( body.ConstraintRefCount != 0 )
            {
              var constraint = body.GetConstraintRef( 0 );
              world.RemoveConstraint( constraint );
              constraint.Dispose( );
            }
            if( body.MotionState != null )
            {
              body.MotionState.Dispose( );
            }
            world.RemoveRigidBody( body );
          }
          else
          {
            world.RemoveCollisionObject( obj );
          }
        }

        //-- Delete Constraints
        //--
        for( var index = world.NumConstraints - 1; index >= 0; index-- )
        {
          var constraint = world.GetConstraint( index );
          world.RemoveConstraint( constraint );
          if( !constraint.IsDisposed ) constraint.Dispose( );
        }

        //-- Delete Collision Shapes
        //--
        for( var index = shapes.Count - 1; index >= 0; index-- )
        {
          shapes[index].Dispose( );
        }
        shapes.Clear( );

        bodies.Clear( );
      }
      catch { }
    }

    public void Dispose( )
    {
      try
      {
        shapes.Dispose( );
        world.Dispose( );
        solver.Dispose( );
        phase.Dispose( );
        dispatch.Dispose( );
        config.Dispose( );
      }
      catch { }
    }
    #endregion
  }

  #endregion
}
